import { Router } from 'express'
import { body, validationResult } from 'express-validator'
import bcrypt from 'bcryptjs'
import jwt from 'jsonwebtoken'
import { supabase } from '../server'
import { logger } from '../utils/logger'
import { asyncHandler, createError } from '../middleware/errorHandler'
import { AuthenticatedRequest, authenticateUser } from '../middleware/auth'

const router = Router()

// Validation rules
const registerValidation = [
  body('email').isEmail().normalizeEmail(),
  body('password').isLength({ min: 8 }).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/),
  body('fullName').trim().isLength({ min: 1, max: 100 }),
  body('gdprConsent').isBoolean().custom(value => value === true)
]

const loginValidation = [
  body('email').isEmail().normalizeEmail(),
  body('password').isLength({ min: 1 })
]

const resetPasswordValidation = [
  body('email').isEmail().normalizeEmail()
]

const changePasswordValidation = [
  body('currentPassword').isLength({ min: 1 }),
  body('newPassword').isLength({ min: 8 }).matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
]

// Helper function to check validation results
const checkValidation = (req: any, res: any) => {
  const errors = validationResult(req)
  if (!errors.isEmpty()) {
    return res.status(400).json({
      success: false,
      message: 'Validation failed',
      errors: errors.array()
    })
  }
  return null
}

// Register new user
router.post('/register', registerValidation, asyncHandler(async (req, res) => {
  const validationError = checkValidation(req, res)
  if (validationError) return validationError

  const { email, password, fullName, displayName, gdprConsent, marketingConsent } = req.body

  try {
    // Check if user already exists
    const { data: existingUser } = await supabase.auth.admin.getUserByEmail(email)
    if (existingUser.user) {
      return res.status(409).json({
        success: false,
        message: 'User with this email already exists'
      })
    }

    // Create user with Supabase Auth
    const { data, error } = await supabase.auth.admin.createUser({
      email,
      password,
      user_metadata: {
        full_name: fullName,
        display_name: displayName || fullName
      },
      email_confirm: process.env.NODE_ENV === 'production'
    })

    if (error) {
      logger.error('User registration failed', { error: error.message, email })
      throw createError('Registration failed: ' + error.message, 400)
    }

    if (!data.user) {
      throw createError('User creation failed', 500)
    }

    // Create user profile
    const { error: profileError } = await supabase
      .from('user_profiles')
      .insert({
        user_id: data.user.id,
        email: data.user.email,
        full_name: fullName,
        display_name: displayName || fullName,
        subscription_status: 'free',
        paper_preferences: {
          categories: [],
          keywords: [],
          authors: [],
          institutions: []
        },
        notification_preferences: {
          email_notifications: marketingConsent || false,
          weekly_digest: marketingConsent || false,
          instant_alerts: false,
          paper_recommendations: marketingConsent || false,
          new_category_papers: false,
          author_updates: false,
          keyword_matches: false,
          push_notifications: false,
          sms_notifications: false,
          digest_frequency: 'weekly',
          quiet_hours: {
            enabled: false,
            start_time: '22:00',
            end_time: '08:00'
          }
        },
        privacy_settings: {
          profile_visibility: 'private',
          search_history_retention: 30,
          data_sharing_consent: false,
          analytics_consent: false,
          marketing_consent: marketingConsent || false,
          research_participation_consent: false,
          data_export_format: 'json'
        },
        account_settings: {
          two_factor_enabled: false,
          login_alerts: true,
          session_timeout: 1440,
          password_strength_requirement: 'medium',
          allowed_login_methods: ['email']
        },
        gdpr_consent: gdprConsent,
        gdpr_consent_date: new Date().toISOString(),
        is_active: true,
        email_verified: !process.env.NODE_ENV === !!'production'
      })

    if (profileError) {
      logger.error('Profile creation failed', { error: profileError.message, userId: data.user.id })
      // Clean up user if profile creation fails
      await supabase.auth.admin.deleteUser(data.user.id)
      throw createError('Profile creation failed', 500)
    }

    // Create default free subscription
    const { error: subscriptionError } = await supabase
      .from('subscriptions')
      .insert({
        user_id: data.user.id,
        plan_type: 'free',
        status: 'active',
        start_date: new Date().toISOString(),
        features: {
          max_saved_papers: 10,
          max_alerts: 3,
          max_search_queries: 50,
          advanced_search: false,
          api_access: false,
          priority_support: false,
          analytics: false,
          export_capabilities: false,
          bulk_download: false,
          collaboration_features: false,
          custom_categories: false
        },
        usage_metrics: {
          saved_papers_count: 0,
          active_alerts_count: 0,
          monthly_searches: 0,
          api_requests_count: 0,
          storage_used_mb: 0,
          last_updated: new Date().toISOString()
        }
      })

    if (subscriptionError) {
      logger.error('Subscription creation failed', { error: subscriptionError.message, userId: data.user.id })
    }

    logger.info('User registered successfully', { 
      userId: data.user.id, 
      email: data.user.email,
      gdprConsent,
      marketingConsent
    })

    res.status(201).json({
      success: true,
      message: process.env.NODE_ENV === 'production' 
        ? 'Registration successful. Please check your email for verification.'
        : 'Registration successful. You can now sign in.',
      user: {
        id: data.user.id,
        email: data.user.email,
        fullName,
        displayName: displayName || fullName,
        emailConfirmed: data.user.email_confirmed_at !== null
      }
    })

  } catch (error) {
    logger.error('Registration error', { error: error instanceof Error ? error.message : String(error), email })
    throw error
  }
}))

// Sign in user
router.post('/login', loginValidation, asyncHandler(async (req, res) => {
  const validationError = checkValidation(req, res)
  if (validationError) return validationError

  const { email, password, rememberMe } = req.body
  const userAgent = req.get('User-Agent')
  const ipAddress = req.ip

  try {
    // Authenticate with Supabase
    const { data, error } = await supabase.auth.signInWithPassword({
      email,
      password
    })

    if (error || !data.user) {
      logger.warn('Login attempt failed', { email, ip: ipAddress, userAgent })
      return res.status(401).json({
        success: false,
        message: 'Invalid email or password'
      })
    }

    // Get user profile
    const { data: profile } = await supabase
      .from('user_profiles')
      .select('*')
      .eq('user_id', data.user.id)
      .single()

    if (!profile) {
      logger.error('User profile not found during login', { userId: data.user.id })
      return res.status(500).json({
        success: false,
        message: 'User profile not found'
      })
    }

    // Update last login timestamp
    await supabase
      .from('user_profiles')
      .update({ 
        last_login: new Date().toISOString(),
        updated_at: new Date().toISOString()
      })
      .eq('user_id', data.user.id)

    // Create session record if rememberMe is enabled
    if (rememberMe) {
      await supabase
        .from('user_sessions')
        .insert({
          user_id: data.user.id,
          session_token: data.session?.access_token || '',
          device_info: {
            user_agent: userAgent,
            ip_address: ipAddress,
            device_type: /Mobile/.test(userAgent || '') ? 'mobile' : 'desktop'
          },
          created_at: new Date().toISOString(),
          expires_at: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), // 30 days
          last_activity: new Date().toISOString(),
          is_active: true
        })
    }

    logger.info('User logged in successfully', { 
      userId: data.user.id, 
      email: data.user.email,
      ip: ipAddress,
      rememberMe
    })

    res.json({
      success: true,
      message: 'Login successful',
      user: {
        id: data.user.id,
        email: data.user.email,
        fullName: profile.full_name,
        displayName: profile.display_name,
        subscriptionStatus: profile.subscription_status,
        lastLogin: profile.last_login
      },
      session: {
        accessToken: data.session?.access_token,
        refreshToken: data.session?.refresh_token,
        expiresAt: data.session?.expires_at
      }
    })

  } catch (error) {
    logger.error('Login error', { error: error instanceof Error ? error.message : String(error), email })
    throw error
  }
}))

// Sign out user
router.post('/logout', authenticateUser, asyncHandler(async (req: AuthenticatedRequest, res) => {
  try {
    const userId = req.user?.id

    if (userId) {
      // Invalidate all user sessions
      await supabase
        .from('user_sessions')
        .update({ is_active: false })
        .eq('user_id', userId)

      logger.info('User logged out', { userId })
    }

    // Sign out from Supabase (this invalidates the current session)
    await supabase.auth.signOut()

    res.json({
      success: true,
      message: 'Logout successful'
    })

  } catch (error) {
    logger.error('Logout error', { error: error instanceof Error ? error.message : String(error) })
    throw error
  }
}))

// Request password reset
router.post('/reset-password', resetPasswordValidation, asyncHandler(async (req, res) => {
  const validationError = checkValidation(req, res)
  if (validationError) return validationError

  const { email } = req.body

  try {
    // Check if user exists
    const { data: existingUser } = await supabase.auth.admin.getUserByEmail(email)
    
    // Always return success for security (don't reveal if email exists)
    if (existingUser.user) {
      const { error } = await supabase.auth.resetPasswordForEmail(email, {
        redirectTo: `${process.env.FRONTEND_URL}/auth/reset-password`
      })

      if (error) {
        logger.error('Password reset request failed', { error: error.message, email })
      } else {
        logger.info('Password reset email sent', { email })
      }
    }

    res.json({
      success: true,
      message: 'If an account with that email exists, a password reset link has been sent.'
    })

  } catch (error) {
    logger.error('Password reset error', { error: error instanceof Error ? error.message : String(error), email })
    throw error
  }
}))

// Change password (authenticated)
router.post('/change-password', authenticateUser, changePasswordValidation, asyncHandler(async (req: AuthenticatedRequest, res) => {
  const validationError = checkValidation(req, res)
  if (validationError) return validationError

  const { currentPassword, newPassword } = req.body
  const userId = req.user?.id

  if (!userId) {
    return res.status(401).json({
      success: false,
      message: 'Authentication required'
    })
  }

  try {
    // Verify current password by attempting to sign in
    const { error: verifyError } = await supabase.auth.signInWithPassword({
      email: req.user?.email || '',
      password: currentPassword
    })

    if (verifyError) {
      return res.status(400).json({
        success: false,
        message: 'Current password is incorrect'
      })
    }

    // Update password
    const { error } = await supabase.auth.admin.updateUserById(userId, {
      password: newPassword
    })

    if (error) {
      logger.error('Password change failed', { error: error.message, userId })
      throw createError('Password change failed: ' + error.message, 400)
    }

    // Invalidate all other sessions
    await supabase
      .from('user_sessions')
      .update({ is_active: false })
      .eq('user_id', userId)

    logger.info('Password changed successfully', { userId })

    res.json({
      success: true,
      message: 'Password changed successfully. Please log in again with your new password.'
    })

  } catch (error) {
    logger.error('Password change error', { error: error instanceof Error ? error.message : String(error), userId })
    throw error
  }
}))

// Verify email
router.post('/verify-email', authenticateUser, asyncHandler(async (req: AuthenticatedRequest, res) => {
  const userId = req.user?.id
  const email = req.user?.email

  if (!userId || !email) {
    return res.status(401).json({
      success: false,
      message: 'Authentication required'
    })
  }

  try {
    // Send verification email
    const { error } = await supabase.auth.resend({
      type: 'signup',
      email
    })

    if (error) {
      logger.error('Email verification send failed', { error: error.message, userId })
      throw createError('Failed to send verification email: ' + error.message, 400)
    }

    logger.info('Verification email sent', { userId, email })

    res.json({
      success: true,
      message: 'Verification email sent successfully'
    })

  } catch (error) {
    logger.error('Email verification error', { error: error instanceof Error ? error.message : String(error), userId })
    throw error
  }
}))

// Refresh token
router.post('/refresh', asyncHandler(async (req, res) => {
  const { refreshToken } = req.body

  if (!refreshToken) {
    return res.status(400).json({
      success: false,
      message: 'Refresh token is required'
    })
  }

  try {
    const { data, error } = await supabase.auth.refreshSession({
      refresh_token: refreshToken
    })

    if (error || !data.session) {
      return res.status(401).json({
        success: false,
        message: 'Invalid refresh token'
      })
    }

    res.json({
      success: true,
      session: {
        accessToken: data.session.access_token,
        refreshToken: data.session.refresh_token,
        expiresAt: data.session.expires_at
      }
    })

  } catch (error) {
    logger.error('Token refresh error', { error: error instanceof Error ? error.message : String(error) })
    throw error
  }
}))

// Get current user info
router.get('/me', authenticateUser, asyncHandler(async (req: AuthenticatedRequest, res) => {
  const userId = req.user?.id

  if (!userId) {
    return res.status(401).json({
      success: false,
      message: 'Authentication required'
    })
  }

  try {
    // Get user profile
    const { data: profile, error } = await supabase
      .from('user_profiles')
      .select('*')
      .eq('user_id', userId)
      .single()

    if (error || !profile) {
      return res.status(404).json({
        success: false,
        message: 'User profile not found'
      })
    }

    // Get subscription info
    const { data: subscription } = await supabase
      .from('subscriptions')
      .select('*')
      .eq('user_id', userId)
      .eq('status', 'active')
      .order('created_at', { ascending: false })
      .limit(1)
      .single()

    res.json({
      success: true,
      user: {
        id: userId,
        email: req.user?.email,
        profile,
        subscription
      }
    })

  } catch (error) {
    logger.error('Get user info error', { error: error instanceof Error ? error.message : String(error), userId })
    throw error
  }
}))

export default router